/*
* Reference GTL Parser for Java
* Copyright (c) 2000-2009 Constantine A Plotnikov
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.sf.etl.parsers.emf;
import java.util.Collection;
import java.util.HashMap;
import net.sf.etl.parsers.LiteralUtils;
import net.sf.etl.parsers.ObjectName;
import net.sf.etl.parsers.ParserException;
import net.sf.etl.parsers.TermParser;
import net.sf.etl.parsers.TermToken;
import net.sf.etl.parsers.Terms;
import net.sf.etl.parsers.Token;
import net.sf.etl.parsers.utils.AbstractTreeParser;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
/**
* EMF term parser.
*
* @author const
*/
public class EMFTermParser
extends
AbstractTreeParser<EObject, EStructuralFeature, EClass, Collection<Object>> {
/** a logger */
private static final java.util.logging.Logger log = java.util.logging.Logger
.getLogger(EMFTermParser.class.getName());
/** A cache of types */
private final HashMap<ObjectName, EClass> typeCache = new HashMap<ObjectName, EClass>();
/** A cache of packages */
private final HashMap<String, EPackage> packageCache = new HashMap<String, EPackage>();
/**
* A constructor
*
* @param parser
* a term parser to use
*/
public EMFTermParser(TermParser parser) {
super(parser);
}
/**
* {@inheritDoc}
*/
@Override
protected EObject createInstance(EClass metaObject, ObjectName name) {
final EClass type = metaObject;
return type.getEPackage().getEFactoryInstance().create(type);
}
/**
* @see net.sf.etl.parsers.utils.AbstractTreeParser#getMetaObject(net.sf.etl.parsers.ObjectName)
*/
@Override
protected EClass getMetaObject(ObjectName name) {
EClass type = typeCache.get(name);
if (type != null) {
return type;
}
EPackage p = packageCache.get(name.namespace());
if (p == null) {
p = EPackage.Registry.INSTANCE.getEPackage(name.namespace());
if (p == null) {
log.severe("Namespace " + name.namespace()
+ " is not registered with parser. (at token "
+ parser.current() + ")");
throw new ParserException("Namespace " + name.namespace()
+ " is not registered with parser.");
}
packageCache.put(name.namespace(), p);
}
type = (EClass) p.getEClassifier(name.name());
if (type == null) {
log.severe("Class " + name.name() + " not found in "
+ name.namespace());
throw new ParserException("Class " + name.name() + " not found in "
+ name.namespace());
}
typeCache.put(name, type);
return type;
}
@Override
protected EStructuralFeature getPropertyMetaObject(EObject rc,
EClass metaObject, TermToken token) {
final EStructuralFeature f = getPropertyMetaObject(rc, metaObject,
token.propertyName().name());
final boolean isList = parser.current().kind() == Terms.LIST_PROPERTY_START;
if (isList != f.isMany()) {
log.severe("Feature " + f.getName() + " in class "
+ f.getContainerClass().getName()
+ " has mismatch in multiplicity with grammar.");
throw new ParserException("Feature " + f.getName() + " in class "
+ f.getContainerClass().getName()
+ " has mismatch in multiplicity with grammar.");
}
return f;
}
/**
* {@inheritDoc}
*/
@Override
protected void setToFeature(EObject rc, EStructuralFeature f, Object v) {
final EObject o = rc;
final EStructuralFeature ef = f;
o.eSet(ef, v);
}
/**
* {@inheritDoc}
*/
@Override
protected void addToFeature(EObject rc, EStructuralFeature f,
Collection<Object> holder, Object v) {
final Collection<Object> l = holder;
l.add(v);
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
protected Collection<Object> startListCollection(EObject rc,
EClass metaObject, EStructuralFeature f) {
final EStructuralFeature ef = f;
if (!ef.isMany()) {
throw new ParserException("Feature is not of collection type: "
+ ef);
}
return (Collection<Object>) (rc).eGet(ef);
}
/**
* {@inheritDoc}
*/
@Override
protected void endListCollection(EObject rc, EClass metaObject,
EStructuralFeature f, Collection<Object> holder) {
// do nothing, collection has been updated in the progress
}
@Override
protected EStructuralFeature getPropertyMetaObject(EObject rc,
EClass metaObject, String name) {
final EClass c = metaObject;
final EStructuralFeature f = c.getEStructuralFeature(name);
if (f == null) {
log.severe("Feature " + name + " not found in " + c.getName()
+ " at " + parser.current());
throw new ParserException("Feature " + name + " not found in "
+ c.getName() + " at " + parser.current());
}
return f;
}
/**
* {@inheritDoc}
*/
@Override
protected Object parseValue(EObject rc, EStructuralFeature f, Token value) {
final EStructuralFeature field = f;
final EClassifier type = field.getEType();
if (type instanceof EEnum) {
return ((EEnum) type).getEEnumLiteral(value.text()).getInstance();
} else if (type instanceof EDataType) {
final EDataType dt = (EDataType) type;
final Class<?> c = dt.getInstanceClass();
if (c == int.class || c == Integer.class) {
return new Integer(LiteralUtils.parseInt(value.text()));
} else if (c == String.class) {
return value.text();
} else {
return dt.getEPackage().getEFactoryInstance().createFromString(
dt, value.text());
}
} else {
throw new ParserException("Unsupported type for value: " + type);
}
}
}